package ar.uba.fi.tp2Unit.displayers.xml;

import java.util.List;

import ar.uba.fi.tp2Unit.framework.TestResult;
import ar.uba.fi.tp2Unit.framework.TestResultDescription;

public class TestSuiteXMLBuilder {
	
	public static TestSuiteXML build(TestResult testResult){
		List<TestResultDescription> results = testResult.getOrderedResults();
		TestSuiteXML rootSuite = new TestSuiteXML();
		if(!results.isEmpty()){
			String rootTestSuiteName = getRootTestSuiteName(results);
			rootSuite.setName(rootTestSuiteName);
			for (TestResultDescription description : results) {
				buildTestSuite(description, rootSuite);
			}
		}
		return rootSuite;
	}
	
	private static String getRootTestSuiteName(List<TestResultDescription> results){
		TestResultDescription firstDescription = results.get(0);
		String[] suitesNames = firstDescription.getTestSuiteName().split("\\.");
		return suitesNames[0];
	}
	
	private static void buildTestSuite(TestResultDescription description, TestSuiteXML testSuite) {
		addTime(description, testSuite);		
		increaseType(description, testSuite);
		increaseTests(testSuite);
		
		if(isTestCase(description)){
			addNewTestCase(description, testSuite);			
		}else{
			updateNextTestSuite(description, testSuite);
		}		 
	}
	
	private static void addTime(TestResultDescription description, TestSuiteXML testSuite) {
		Double totalTime = Double.valueOf(testSuite.getTime())	+ Double.valueOf(description.getElapsedTime());
		testSuite.setTime(String.valueOf(totalTime));
	}
	
	private static void increaseType(TestResultDescription description, TestSuiteXML testSuite) {
		if (isFailure(description)) {
			addFailure(testSuite);
		}
		if (isError(description)) {
			addError(testSuite);
		}
	}

	private static boolean isFailure(TestResultDescription description){
		return description.getType().equals("FAIL");
	}

	private static void addFailure(TestSuiteXML testSuite) {
		Integer totalFailures = Integer.valueOf(testSuite.getFailures()) + 1;
		testSuite.setFailures(String.valueOf(totalFailures));
	}

	private static boolean isError(TestResultDescription description){
		return description.getType().equals("ERROR");
	}
	
	private static void addError(TestSuiteXML testSuite) {
		Integer totalErrors = Integer.valueOf(testSuite.getErrors()) + 1;
		testSuite.setErrors(String.valueOf(totalErrors));
	}
	
	private static void increaseTests(TestSuiteXML testSuite) {
		Integer totalTests = Integer.valueOf(testSuite.getTests()) + 1;
		testSuite.setTests(String.valueOf(totalTests));
	}

	private static boolean isTestCase(TestResultDescription description){
		String[] suitesNames = description.getTestSuiteName().split("\\.");
		return suitesNames.length == 1;
	}
	
	private static void addNewTestCase(TestResultDescription description, TestSuiteXML testSuite) {
		TestCaseXML testCase = new TestCaseXML();
		testCase.setName(description.getTestCaseName());
		testCase.setTime(description.getElapsedTime());
		testSuite.getTestCases().add(testCase);
		if(isError(description)){
			testCase.setError(new ErrorXML(description.getMessage()));
		}
		if(isFailure(description)){
			testCase.setFailure(new FailureXML(description.getMessage()));
		}
	}
		
	private static void updateNextTestSuite(TestResultDescription description, TestSuiteXML testSuite) {
		removeThisTestSuiteNameFromDescription(description);
		String nextTestSuiteName = getFirstTestSuiteName(description);
		if(existsTestSuiteWithName(nextTestSuiteName, testSuite)){				
			updateTestSuite(description, nextTestSuiteName, testSuite);
		}else{
			addNewTestSuite(description, nextTestSuiteName, testSuite);
		}
	}
	
	private static void removeThisTestSuiteNameFromDescription(TestResultDescription description) {
		String[] nextSuitesNames = description.getTestSuiteName().split("\\.",2);
		description.setTestSuiteName(nextSuitesNames[1]);
	}
	
	private static String getFirstTestSuiteName(TestResultDescription description){
		String[] suitesNames = description.getTestSuiteName().split("\\.");
		return suitesNames[0];
	}
	
	private static boolean existsTestSuiteWithName(String name, TestSuiteXML testSuite) {
		for (TestSuiteXML suite : testSuite.getTestSuites()) {
			if(name.equals(suite.getName())){
				return true;
			}
		}
		return false;
	}
	
	private static void updateTestSuite(TestResultDescription description,	String nextTestSuiteName, TestSuiteXML testSuite) {
		TestSuiteXML existingTestSuite = getTestSuiteXMLByName(nextTestSuiteName, testSuite);
		buildTestSuite(description, existingTestSuite);	
	}	
	
	private static TestSuiteXML getTestSuiteXMLByName(String name, TestSuiteXML testSuite){
		TestSuiteXML result = null;
		for (TestSuiteXML suite : testSuite.getTestSuites()) {
			if(name.equals(suite.getName())){
				result = suite;
			}
		}
		return result;
	}
		
	private static void addNewTestSuite(TestResultDescription description, String nextTestSuiteName, TestSuiteXML testSuite) {
		TestSuiteXML newSuite = new TestSuiteXML();
		newSuite.setName(nextTestSuiteName);
		testSuite.getTestSuites().add(newSuite);
		buildTestSuite(description, newSuite);
	}

}
